﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Sakura.Media.AviSynth
{
	/// <summary>
	/// 表示 AVS 环境使用的一个值。
	/// </summary>
	public class AvsValue
	{
		/// <summary>
		/// 缓存的值。
		/// </summary>
		private object value;

		/// <summary>
		/// 原始内部值。
		/// </summary>
		private Native.AvsValue rawValue;

		/// <summary>
		/// 初始化一个新的值。
		/// </summary>
		/// <param name="value">要初始化的值。</param>
		private AvsValue(object value)
		{
			this.value = value;
		}

		/// <summary>
		/// 从本机对象初始化一个新的值。
		/// </summary>
		/// <param name="rawValue">要初始化的值。</param>
		private AvsValue(Native.AvsValue rawValue)
		{
			this.rawValue = rawValue;
		}

		/// <summary>
		/// 更新缓存值。
		/// </summary>
		private void UpdateValue()
		{
			this.value = ParseRawValue(this.rawValue);
		}

		private void UpdateRawValue()
		{
			this.rawValue = ParseValue(this.value);
		}

		/// <summary>
		/// 从本机对象中创建值。
		/// </summary>
		/// <param name="value">要创建的值。</param>
		/// <returns>创建后的结果。</returns>
		internal static AvsValue CreateFromNative(Native.AvsValue value)
		{
			return new AvsValue(ParseRawValue(value));
		}

		/// <summary>
		/// 解析一个本机 <see cref="AvsValue"/> 对象的值。
		/// </summary>
		/// <param name="rawValue">要解析的值。</param>
		/// <param name="env">解析时相关的环境信息。</param>
		/// <returns>解析后的结果。</returns>
		private static object ParseRawValue(Native.AvsValue rawValue, AvsEnvironment env)
		{
			switch (rawValue.Type)
			{
				case Native.AvsValueType.Void:
					return null;
				case Native.AvsValueType.Boolean:
					return rawValue.Value.Boolean != 0;
				case Native.AvsValueType.Integer:
					return rawValue.Value.Integer;
				case Native.AvsValueType.Float:
					return rawValue.Value.FloatPtr;
				case Native.AvsValueType.String:
					return rawValue.Value.String;
				case Native.AvsValueType.Clip:
					return Native.NativeMethods.avs_take_clip(rawValue, env.ptr);
				case Native.AvsValueType.Error:
					throw new NotImplementedException();
				case Native.AvsValueType.Array:
					// TODO: 考虑使用非托管代码增加性能。
					var arr = new AvsValue[rawValue.ArraySize];
					var itemSize = Marshal.SizeOf(typeof(Native.AvsValue));
					var p = rawValue.Value.Array;
					for (var i = 0; i < arr.Length; i++)
					{
						var n = (Native.AvsValue)Marshal.PtrToStructure(p, typeof(Native.AvsValue));
						arr[i] = CreateFromNative(n);
						p += itemSize;
					}
					return arr;
				default:
					throw new NotSupportedException();
			}
		}

		/// <summary>
		/// 解析一个值并转换为本机对象的值。
		/// </summary>
		/// <param name="value">要解析的值。</param>
		/// <returns>转换后获得的本机对象。</returns>
		private static Native.AvsValue ParseValue(object value)
		{
			if (value == null)
			{
				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.Void;
				return result;
			}
			else if (value is int)
			{
				var i = (int)value;

				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.Integer;
				result.Value.Integer = i;

				return result;
			}
			else if (value is float)
			{
				var i = (float)value;

				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.Float;
				result.Value.FloatPtr = i;

				return result;
			}
			else if (value is string)
			{
				var i = (string)value;

				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.String;
				result.Value.String = i;

				return result;
			}
			else if (value is bool)
			{
				var i = (bool)value;

				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.Boolean;
				result.Value.Boolean = (byte)(i ? 1 : 0);

				return result;
			}
			else if (value is AvsClip)
			{
				var i = (AvsClip)value;

				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.Clip;
				Native.NativeMethods.avs_set_to_clip(result, i.ptr);

				return result;
			}
			else if (value is AvsValue[])
			{
				var data = (AvsValue[])value;

				var result = new Native.AvsValue();
				result.Type = Native.AvsValueType.Array;

				var itemSize = Marshal.SizeOf(typeof(Native.AvsValue));
				var mem = Marshal.AllocHGlobal(itemSize * data.Length);

				for (int i = 0; i < data.Length; i++)
				{
					Marshal.StructureToPtr(data[i], mem, true);
					mem += itemSize;
				}

				return result;
			}
			else
			{
				throw new ArgumentException("不支持此类型的值，AvsValue 只能接收基本类型或者数组。", "value");
			}
		}
	}
}
